[Разбор] Полный разбор проекта MyBlog

1. Введение

MyBlog – это легковесное асинхронное веб-приложение для ведения личного блога и галереи нейросетевых артов. Построено на базе фреймворка FastAPI. Основная идея проекта – полная автономность. Отсутствие тяжёлых внешних зависимостей (баз данных) и работа через высокоскоростное In-memory кэширование файловой системы. Это сочетает надёжность хранения в плоских файлах (Markdown) с мгновенным откликом интерфейса. Это делает проект идеальным для self-hosted развёртывания.

2. Архитектура и серверная логика: main.py

2.1 Инфраструктурные решения

Проект спроектирован с учётом работы за Reverse Proxy (Nginx/Traefik), что делает его максимально гибким для различных сценариев хостинга.

@app.middleware("http")  
async def add_proxy_headers(request: Request, call_next):  
    path_prefix = request.headers.get("X-Forwarded-Prefix")  
    if path_prefix:  
        request.scope["root_path"] = path_prefix  
    return await call_next(request)

2.2 Работа с базой данных (Flat-file DB)

Архитектура проекта исключает SQL. Мы используем Flat-file approach:

Плюсы: Бэкап блога – это просто копирование папки. Нет оверхеда на коннекты к БД. Скорость доступа к списку постов больше не ограничена скоростью дисковой подсистемы.
Минусы: Отсутствие транзакционности, что полностью нивелируется использованием кэша и атомарных операций записи для персонального блога.

2.3 Авторизация и механизм приватных статей

Реализована через SessionMiddleware на базе зашифрованных Cookies. Функция require_auth выступает барьером для всех деструктивных действий.

Внедрена система дискретных кодов доступа для статей с префиксом [P].

2.4 Контент-пайплайн (Markdown)

Сервер выполняет базовую конвертацию Markdown в HTML с расширениями fenced_code, tables, nl2br, sane_lists, attr_list, md_in_html и toc. Расширенный синтаксис заметок Obsidian (блоки Callouts вроде [!INFO], [!WARNING], маркерное выделение ==текст== и интерактивные чек-листы [x]) дорабатывается на клиентской стороне скриптами пост-процессинга в article.html. Это объединяет надёжность серверного HTML с гибкостью визуального обогащения.

2.5 Автоматизация путей через Post-processing

html = html.replace('/blog/static/', '/blog/static/')

Механизм автоматически заменяет относительные пути на абсолютные перед отдачей страницы пользователю. Это гарантирует, что медиаконтент будет корректно отображаться вне зависимости от вложенности URL статьи, а запросы к статике будут мгновенно обрабатываться через Nginx (блок /blog/static/), минуя Python-логику. Это обеспечивает «железную» стабильность отображения картинок и видео.

2.6 Функциональные эндпоинты и безопасность хранилища

2.6.1 Галерея и Промты

Галерея – это не просто список картинок. Сервер связывает файлы изображений с их текстовыми описаниями (промтами):

2.6.2 Универсальный медиа-хаб и безопасность загрузки

2.7 Шаблонизация, типографика и фильтры Jinja2

В конфигурацию шаблонизатора внедрён кастомный фильтр insert_zwsp:

templates.env.filters.update({"insert_zwsp": insert_zero_width_spaces})

Он расставляет невидимые мягкие переносы (\u200b / ZWSP) исключительно в аномально длинные последовательности символов (более 20 символов), не затрагивая HTML-теги. Порог в 20 знаков выбран осознанно: это полностью исключает разрывы обычных длинных русских слов и сохраняет целостность типографики. Фильтр надёжно спасает мобильную вёрстку от распирания сверхдлинными ссылками и техническими строками.

2.7.1 Типографика и ёфикация

Проект следует строгому стандарту ёфикации контента. Использование буквы «ё» во всех материалах и заголовках блога – фундаментальное правило чистоты языка. Фильтр insert_zwsp бережно защищает слова с буквой «ё» от некорректных переносов, сохраняя эстетику авторского текста

2.8 Визуальный конструктор: Blog Master

В экосистему MyBlog интегрирован мощный визуальный конструктор, позволяющий создавать профессиональные обложки и карточки-анонсы в стиле Flexy без использования Photoshop.

[!WARNING] Исключительно для ПК
Конструктор является профессиональным инструментом и доступен только в десктопной версии. В мобильных браузерах доступ намеренно ограничен, так как корректная вёрстка и рендеринг шрифтов требуют строго определённой ширины экрана. Только на ПК рабочая область гарантирует режим Pixel Perfect: когда финальный файл в форматах PNG или WebP в точности соответствует тому, что вы видите на своём мониторе, без нежелательных переносов строк или искажений.


Благодаря интеллектуальному сбросу масштаба перед рендерингом, вы получаете кристально чистое изображение в исходном высоком разрешении, независимо от выбранного формата холста.

3. Клиентская часть: main.html (Главная страница)

3.1 UI/UX и дизайн-система

Дизайн выполнен в стиле Modern Dark Minimalism.
В свежей итерации интерфейс стал более симметричным и сфокусированным. Основные изменения коснулись визуальной иерархии:

3.2 Динамическая генерация категорий (The Tag System)

Одной из ключевых фишек интерфейса является автоматическая трансформация структуры карточек при загрузке страницы. Система на лету считывает метаданные из названий файлов и модифицирует DOM-дерево для каждой статьи.

Техническая реализация:

// Ищем все конструкции в квадратных скобках  
const matches = fullName.match(/\[(.*?)\]/g);  
let catName = "";  

if (matches) {  
matches.forEach(m => {  
const content = m.slice(1, -1);  
if (content.toUpperCase() === 'P') {  
item.dataset.private = "true"; // Флаг приватности [P]  
} else {  
catName = content; // Имя категории  
}  
});  
}

Этот подход полностью избавляет от ручного прописывания тегов в базе данных. Система сама строит дерево категорий и формирует облако тегов в верхней части страницы (categoryBox) исключительно на базе реальных префиксов в именах файлов. Плавное переключение между разделами происходит мгновенно на стороне клиента, обеспечивая безупречный UX.

3.3 Система приоритетов (Sticky Posts)

В скрипт initCategories интегрирован алгоритм проверки символа !.

[!WARNING] Важно
Символ ! должен стоять самым первым в названии файла (например, ![Soft] Настройка.md), иначе скрипт не распознает его как команду для закрепления.

3.4 Клиентская фильтрация, поиск и Lazy Rendering

Вместо того чтобы нагружать сервер запросами при каждом вводе буквы, поиск реализован на стороне клиента (Client-side Filtering).

  1. Поиск: Работает мгновенно через includes() по атрибутам data-name.
  2. Категории: Переключаются без перезагрузки страницы. Пользователь видит результат сразу.
  3. Счётчик: Элемент #articles-count динамически обновляется, показывая количество найденных записей. Это отличный UX-паттерн.
  4. Интеллектуальная подгрузка (Lazy Rendering): Для обеспечения стабильных 60 FPS при поиске внедрена система постепенного вывода контента. По умолчанию на экран выводится первая сотня совпадений, а доступ к остальному архиву осуществляется через кнопку «Показать ещё». Это исключает «фризы» браузера при работе с тысячами записей, сохраняя при этом полный доступ ко всей базе статей без перезагрузки страницы.

3.4.1 AJAX-управление (Админ-панель)

Для авторизованных пользователей предусмотрена возможность управления архивом:
- Safe Delete: Удаление статей происходит через fetch() с подтверждением confirm(). На стороне сервера в эндпоинте delete_article имя статьи проходит через urllib.parse.unquote(), что гарантирует безошибочное нахождение и удаление файлов с кириллицей, пробелами и спецсимволами. Массовая очистка архива отправляется формой на абсолютный маршрут /blog/articles/delete_all.
- CSRF-защита (базовая): Наличие кастомного заголовка X-Requested-With: XMLHttpRequest в AJAX-запросах защищает от межсайтовой подделки (CSRF), так как браузер блокирует отправку нестандартных заголовков со сторонних ресурсов без явного разрешения CORS.

3.4.2 Технические особенности вёрстки


3.5 Обоснование фронтенд-архитектуры

  1. No Framework (Vanilla JS): Использование чистого JavaScript – осознанный выбор. Для такого функционала React или Vue были бы избыточны (overkill), а текущий код весит всего пару килобайт и работает быстрее любого фреймворка.
  2. Jinja2 Hydration: Начальный список статей рендерится сервером, а затем «подхватывается» скриптами для фильтрации. Это сохраняет SEO-показатели (поисковики видят все ссылки) при полной интерактивности.
  3. LocalStorage Bypass: В отличие от предыдущих модулей, здесь данные полностью контролируются сервером, а фронтенд лишь управляет их отображением.

Плюсы:

Минусы:

4. Движок чтения статей (Article View Engine)

Этот модуль (article.html) отвечает за рендеринг и интеллектуальное обогащение контента. Основная фишка заключается в Post-processing на стороне клиента. Мы не просто выводим HTML, мы его дорабатываем авторскими скриптами для достижения безупречного UX и полной автономности.

4.1 Клиентская обработка контента (Smart Post-processing)

4.1.1 Оживление текстовых ссылок

Стандартный парсер Markdown часто игнорирует простые текстовые URL, не превращая их в кликабельные элементы. Наш скрипт автоматизирует этот процесс: он находит все строки в тексте соответствующие паттерну https://, и оборачивает их в активные HTML-ссылки. Это гарантирует корректную навигацию, даже если автор статьи забыл использовать синтаксис разметки.

function linkify(node) {
  const urlRegex = /(?<!["=])(https?:\/\/[^\s<]+)/g;
  let child = node.firstChild;
  while (child) {
    if (child.nodeType === 3) { // Работаем только с текстовыми узлами
      const text = child.nodeValue;
      if (urlRegex.test(text)) {
        const tempDiv = document.createElement('div');
        tempDiv.innerHTML = text.replace(urlRegex, (url) => 
          `<a href="${url}" target="_blank" rel="noopener noreferrer">${url}</a>`
        );
        while (tempDiv.firstChild) node.insertBefore(tempDiv.firstChild, child);
        const next = child.nextSibling;
        node.removeChild(child);
        child = next;
        continue;
      }
    } else if (child.nodeType === 1 && !['A', 'PRE', 'BUTTON', 'SCRIPT', 'STYLE'].includes(child.tagName)) {
      linkify(child);
    }
    child = child.nextSibling;
  }
}

Инженерная деталь: Используется регулярное выражение с Lookbehind (?<!["=]). Это критически важный предохранитель: он не даёт скрипту испортить уже существующие HTML-теги, где URL находится внутри атрибутов src или href.

4.1.2 Динамический парсинг заголовка (Title Engine)

Здесь применяется логика автоматических визуальных меток. Если заголовок статьи в Markdown-файле имеет вид ![OS] Настройка Windows, скрипт выполняет три задачи:

  1. Обработка закрепов: Находит символ ! в начале строки и помечает статью как приоритетную, добавляя иконку гвоздика 📌.
  2. Выделение категорий: Извлекает тег [OS] и преобразует его в эффектный отдельный графический элемент (category-label) над основным названием.
  3. Очистка заголовка: Полностью удаляет технические префиксы (! и []) из текста <h1>.

В актуальной версии движка обработка H1 была вынесена из общего цикла JavaScript-обработки текстовых блоков. Теперь за его отображение отвечают строгие CSS-правила с приоритетом !important. Это гарантирует режим Pixel Perfect: заголовок всегда остаётся видимым, не «схлопывается» и корректно переносится по словам даже при наличии сложных символов (например, длинного тире), что исключает любые конфликты со скриптами пост-процессинга.

[!WARNING] Важно
Порядок символов в названии файла критичен: первым должен идти восклицательный знак, затем категория в скобках, и только потом название. Пример: ![Soft] Твикер.md.

4.1.3 Система умных спойлеров (Media Spoiler Engine)

4.2 Код и адаптивные таблицы (Code & Tables Engine)

4.2.1 Интеллектуальное оглавление (Smart TOC)

4.2.2 Блоки кода и механизм копирования (Code Blocks & Copy Engine)

Любой блок программного кода автоматически оборачивается в контейнер .code-block, куда динамически инжектируется кнопка копирования.

4.2.3 Адаптивные таблицы (Responsive Data Tables)

Таблицы в вебе — это один из самых «капризных» элементов. Если их просто оставить как есть, они напрочь ломают мобильную вёрстку. В MyBlog реализовано изящное гибридное решение:

4.2.3.1 Серверный этап (Генерация)

Расширение tables в библиотеке markdown превращает стандартную Markdown-разметку:

| Заголовок 1 | Заголовок 2 |
|-------------|-------------|
| Текст 1     | Текст 2     |

в чистый HTML-код: теги <table>, <thead>, <tbody>, <tr> (строки) и <td> (ячейки). Сами по себе эти теги не умеют подстраиваться под размер экрана.

4.2.3.2 Фронтенд-этап (Адаптация)

JS-скрипт в модуле article.html находит все сгенерированные таблицы и оборачивает каждую в контейнер div.table-wrapper со свойством overflow-x: auto. Внутри статьи появляется компактная область, которую можно плавно скроллить пальцем, не ломая общую ширину страницы.

4.3 Дизайн и типографика статьи (Article View Engine)

Модуль рендеринга контента следует философии Modern Dark Minimalism, обеспечивая безупречный UX при чтении сложных технических материалов:

Визуальная иерархия дополнена умными списками: маркеры ul/ol теперь имеют тот же мягкий оттенок #b0bccd, что и основной текст, и вынесены за пределы текстового блока (list-style-position: outside). Это сохраняет строгий ритм чтения и предотвращает визуальное "слипание" перечислений с основным контентом.

[!WARNING] Важно
Использование фильтра размытия (blur) на кнопке не только выглядит эффектно, но и решает проблему читаемости текста, который оказывается «под» кнопкой во время скролла.
Технический акцент: Весь визуал реализован на чистом CSS без внешних шрифтовых иконок или тяжёлых UI-китов, что гарантирует мгновенную отрисовку страницы (LCP) даже на слабых устройствах.

4.3.1 Нативный Медиа-интерфейс

Для сохранения единого визуального кода и высокого быстродействия проект отказывается от тяжёлых кастомных плееров в пользу нативных элементов браузера. Чтобы стандартные компоненты ОС (на Windows, Android или iOS) не выбивались из общего стиля, применена адаптация через CSS-фильтры:

 /* Инверсия цветов с коррекцией тона под тёмную тему */
 audio { filter: invert(90%) hue-rotate(180deg) brightness(1.1); }

Это решение позволяет системным контроллерам выглядеть как органичная часть дизайна Modern Dark Minimalism, сохраняя при этом аппаратную оптимизацию и нативное управление громкостью.
Структурированные плейлисты: Для группировки аудиоматериалов реализована поддержка компактных плейлистов на базе связки <figure> и <figcaption>. Подписи к трекам наследуют общую типографику параграфов, превращая набор плееров в упорядоченную библиотеку. Такой подход гарантирует безупречную работу медиа-контента даже на старых устройствах, где кастомные JS-плееры могли бы вызвать задержки в отрисовке (LCP).

4.4 Экспорт (Portable Engine) и системная интеграция (Share API)

Вместо стандартной печати в проект интегрирован механизм сборки автономного HTML-пакета. При нажатии на кнопку «Экспорт» происходит не просто копирование текущего DOM-дерева, а его интеллектуальная «санация»:
- Бинарная инъекция и прогресс: Скрипт асинхронно конвертирует все изображения, аудио и видео в формат Base64. Процесс сопровождается динамическим прогресс-баром (Сборка: X%), что обеспечивает визуальный отклик при работе с объёмными медиа-массивами.
- Интеллектуальная нормализация медиа: В процессе сборки пакета система автоматически декодирует URL-пути, извлекает оригинальные имена файлов (включая кириллицу) и внедряет их в атрибуты title и download. Это подготавливает автономный файл к корректному распознаванию системными загрузчиками ОС.
- Атомарная очистка DOM: Перед генерацией финального Blob-объекта скрипт проводит «санацию» дерева: удаляет интерактивное оглавление (TOC), скрывает служебные кнопки и возвращает блокам кода их первозданный вид (pre), избавляя оффлайн-копию от лишнего «мусора».
- Восстановление кода: Тегам pre возвращается их первозданный вид, без внедрённых скриптами статус-баров. Это гарантирует, что экспортированная статья будет содержать безупречный, валидный код, максимально приближённый к исходному Markdown-оригиналу.
- Сохранение приватности при экспорте: Система спойлеров полностью переносима. При экспорте статьи в автономный HTML-файл все атрибуты data-spoiler и соответствующие CSS-правила сохраняются. Это гарантирует, что даже в оффлайн-копии статьи «горячий» контент останется скрытым до осознанного клика пользователя, сохраняя приватность просмотра вне зависимости от наличия связи с сервером.

Результат: Пользователь получает один .html файл, который открывается в любом браузере без интернета и внешних зависимостей. Это превращает блог в инструмент создания переносимой документации, которую можно хранить вечно.

Цифровая сохранность типографики: Важной особенностью экспорта является полная консервация визуального стиля. Автономная копия статьи сохраняет абсолютную верность типографике: все результаты работы серверных фильтров, включая принудительную ёфикацию и невидимые пробелы (ZWSP), бережно переносятся в HTML-пакет. Это гарантирует, что даже через десятилетия оффлайн-копия будет выглядеть именно так, как её задумал автор, без «разрывов» вёрстки на новых устройствах.

4.4.1 Интеграция с нативной системой (Share API)

Этот модуль отвечает за бесшовную передачу данных между веб-приложением и операционной системой пользователя.

4.4.2 Смарт-нормализация URL

Кнопка Поделиться не просто копирует URL, она выполняет глубокую очистку и интеллектуальное экранирование адреса:

// Декодируем текущий URL, чтобы работать с чистой кириллицей
let currentUrl = decodeURI(window.location.href);

// Принудительно кодируем спецсимволы, критичные для парсеров:
const beautyUrl = currentUrl
     .replace(/!/g, '%21')
     .replace(/\[P\]/g, '%5B%50%5D')
     .replace(/\[/g, '%5B')
     .replace(/\]/g, '%5D')
     .replace(/ /g, '%20');

Инженерная деталь: Использование decodeURI позволяет получить «чистую» кириллицу, а ручное переопределение кодирования для маркера [P], символов !, [, ] и пробелов гарантирует, что системные теги блога не будут «съедены» парсерами мессенджеров. Это делает ссылку полностью безопасной для передачи в Telegram, Discord или WhatsApp, сохраняя её валидность и аккуратный внешний вид.

4.4.3 Безопасность и управление


4.4.4 Вердикт по модулю Article

Этот шаблон превращает простой текстовый файл в полноценную веб-страницу.
Главный плюс: Весь функционал (копирование кода, бейджи, ссылки) работает автономно и мгновенно.
Минус: Если в статье будет 500 блоков кода, инициализация 500 кнопок копирования может занять доли микросекунды (что на самом деле незаметно, но мы же задроты, верно?).

Галерея предназначена для отображения нейросетевых артов и видео. Основная техническая сложность здесь – работа с контентом разной высоты без создания визуальных дыр в сетке.

5.1 Masonry Grid: Математика вёрстки

Вместо использования тяжёлых библиотек (типа Isotope или Masonry.js), в проект интегрирован самописный легковесный алгоритм на Vanilla JS.

  1. Динамическое распределение: Система определяет количество колонок исходя из ширины экрана (от 1 до 3). Используется массив colHeights, инициализированный нулями.
  2. Алгоритм кратчайшей колонки: Для каждого элемента вычисляется его позиция: он всегда встаёт в ту колонку, которая в данный момент является самой кратчайшей. Это исключает появление пустых зон (дыр) при разной высоте контента.
  3. GPU-acceleration: Для перемещения карточек используется translate3d вместо изменения top/left. Это задействует аппаратное ускорение видеокарты, обеспечивая плавность 60 FPS при перестроении сетки.
  4. Адаптивная деградация: На экранах менее 700px алгоритм Masonry автоматически отключается (position: relative), переходя в режим классического вертикального потока. Это экономит ресурсы CPU на слабых смартфонах.
  5. Математическая реализация:
const minH = Math.min(...colHeights), idx = colHeights.indexOf(minH);
item.style.transform = `translate3d(${idx * (itemWidth + gap)}px, ${minH}px, 0)`;

Страховка рендеринга:
Поскольку высота карточки неизвестна до загрузки медиа, вызов resizeInstance дублируется трижды: по событию load, через setTimeout(500) и отдельно по событию onloadedmetadata для каждого видео. Это гарантирует, что сетка не «поплывёт» после того, как тяжёлое видео подгрузит свои размеры.

Динамический расчёт контейнера:
В конце расчёта скрипт находит максимальное значение в colHeights и задаёт высоту родителю: gallery.style.height = Math.max(...colHeights) + "px". Без этого шага последующие элементы страницы (например, футер) «наехали» бы на галерею из-за абсолютного позиционирования элементов.

5.2 Воспроизведение медиа и полноэкранный лайтбокс

5.2.1 Поддержка видео

Галерея нативно поддерживает формат MP4. Для экономии ресурсов и создания "живого" эффекта превью:

5.2.2 Умный Лайтбокс (Просмотрщик)

Реализована собственная система полноэкранного предпросмотра. При клике на медиаконтент создаётся оверлей с динамическим размытием заднего плана (backdrop-filter: blur(15px)). Это программно изолирует внимание пользователя на выбранном арте или видео, создавая глубокое погружение и превращая просмотр в полноценный визуальный опыт. Контент внутри лайтбокса адаптивен и ограничен по высоте (95vh), что исключает появление паразитных полос прокрутки и гарантирует корректное отображение на любых типах дисплеев.

Интеллектуальный рендеринг в модальном окне: Скрипт лайтбокса использует прямые ссылки на рабочие медиа-ресурсы и принудительно сбрасывает CSS-фильтры через content.style.filter = "none". Это гарантирует мгновенное отображение чёткого контента, даже если превью в сетке было сильно заблюрено

5.3 Система умных спойлеров (NSFW Spoiler Engine)

В логику рендеринга медиа-карточек интегрирован алгоритм автоматической защиты контента:

- Автоматический блюр в Masonry: Сетка Галереи обучена мгновенно распознавать файлы с суффиксом _S в имени (например, art_S.jpg). Такие карточки по умолчанию рендерятся с экстремальным размытием (blur 40px) и снабжаются сервисным бейджем «18+». Это позволяет безопасно смешивать любой контент в одной ленте, сохраняя эстетику и приличие интерфейса.
- Интерактивная интрига и Лайтбокс: При наведении курсора на заблюренную плитку эффект размытия мягко снижается до 25px, создавая визуальный отклик. Полное «раскрытие» контента происходит исключительно в полноэкранном лайтбоксе: JS-движок подхватывает чистый источник (src) и программно нейтрализует все фильтры цензуры, демонстрируя оригинал в идеальном качестве.
- Бесшовный визуальный код: Использование CSS-фильтров вместо замены исходников позволяет сохранить целостность Masonry-сетки и избежать «прыжков» вёрстки при взаимодействии с контентом. Это гарантирует стабильность позиций элементов даже при экстремальных значениях размытия.

5.4 Интеграция с данными ИИ (Prompt Management)

Каждая карточка в галерее – это контейнер для метаданных.


5.5 Плюсы и минусы решения

Плюсы:

  1. Zero Library: Отсутствие внешних JS-зависимостей делает страницу экстремально лёгкой.
  2. GPU acceleration: Плавная перестройка сетки при изменении размера окна браузера.
  3. Flexibility: Галерея одинаково хорошо работает как с горизонтальными, так и с вертикальными артами.

Минусы:

1. Initial Load: Функция resizeInstance должна ждать полной загрузки изображений, чтобы узнать их высоту (window.onload). На очень медленном интернете сетка может "прыгнуть" во время инициализации. Решается введением фиксированных пропорций для картинок (aspect-ratio), если они известны заранее.

6. Загрузка контента и администрирование (Data Ingestion)

Вся работа с контентом разделена на два специализированных шлюза: upload_media.html и upload_article.html. Они построены на базе нативного JavaScript и FormData, без применения сторонних библиотек.

6.1 Стек и UX-инженерия

Оба загрузчика объединены общим визуальным стилем тёмной темы и реактивным поведением интерфейса:

6.1.1 Интерактивный Drag-and-Drop

Вместо стандартных элементов выбора файлов реализована интерактивная область #dropzone:
- Событийная модель: перехват dragover, dragleave и drop с визуальной сменой рамок и лёгким увеличением масштаба (scale(1.01)).
- Пакетная обработка: поддержка одновременной отправки пачки файлов через единый поток.

6.1.2 Честный трекинг прогресса (XHR over Fetch)

Для отправки данных намеренно выбран XMLHttpRequest, а не fetch. Это архитектурное решение продиктовано необходимостью перехвата события xhr.upload.onprogress, что даёт плавный побайтовый расчёт процентов (progress-bar) в реальном времени даже при передаче гигабайтных видеофайлов.


6.2 Глубокий разбор: Медиа-хаб (upload_media)

Модуль спроектирован как полноценный файловый менеджер для ассетов блога:

6.2.1 Динамическая адресация и теги

6.2.2 Встроенный NSFW-процессинг

Интегрированный чекбокс «Применить блюр (_S)» передаёт флаг is_blur=true. Сервер автоматически дописывает суффикс _S к имени файла, благодаря чему медиа сразу попадает в Галерею с наложенным защитным блюром (40px) и плашкой 18+, исключая случайный показ деликатного контента.

6.2.3 Интегрированный проводник (Live Explorer)

При клике на имя папки разворачивается асинхронный менеджер fileManager (эндпоинт /list_files/{folder_name}): карточки позволяют в один клик скопировать готовый относительный путь /blog/static/... для прямой вставки в Markdown или быстро удалить ненужный файл.


6.3 Глубокий разбор: Загрузка статей (upload_article)

Модуль оптимизирован под быстрый текстовый пайплайн (Obsidian / Markdown):

6.3.1 Валидация и интеллектуальная мутация имён

Фронтенд пропускает исключительно файлы с расширением .md. Перед отправкой через FormData скрипт перехватывает оригинальные имена файлов и модифицирует их на основе выбранных чекбоксов:
- Закреп: чекбокс pinCheck добавляет маркер ! в самое начало имени.
- Приватность: чекбокс privCheck внедряет префикс [P].
- Санитария: скрипт автоматически срезает старые дублирующие префиксы, исключая появление артефактов вида !! [P] [P] Название.

6.3.2 Автоматизация редиректа

После успешного ответа сервера (HTTP 200) статус-бар подтверждает публикацию, и через секунду скрипт выполняет мягкий редирект пользователя на главную страницу /blog/main.


6.3.3 Обоснование инфраструктурных решений

  1. Zero External Libraries: модуль drag-and-drop и файловый менеджер написаны на чистом Vanilla JS, что гарантирует мгновенную загрузку страниц (~3–5 Кб).
  2. Борьба с залипанием дескрипторов (Stale Handle Bypass): чтение байтов через await file.arrayBuffer() и упаковка в свежий Blob при Drag-and-Drop принудительно вычитывают данные с диска в память. Это полностью исключает баг Chromium-браузеров с отправкой устаревшего кэшированного дескриптора при повторном перетаскивании только что изменённого файла.
  3. Сброс состояния инпута: событие onclick на элементе выбора файлов обнуляет value, гарантируя надёжное срабатывание onchange даже при повторном выборе файла с тем же именем через системный диалог.
  4. Эшелонированная безопасность (Defense in Depth):
    - Клиентская валидация типов (accept и JS-фильтры).
    - Серверная чистка имён через регулярные выражения в Python, блокирующая атаки Path Traversal и инъекции спецсимволов.
  5. Mobile-First адаптивность: высота дропзоны динамически уменьшается на экранах до 600px, а элементы управления переводятся в удобный сенсорный формат.

6.4 Административные операции (Destructive Actions)

Проект включает в себя функции моментальной очистки архива:
- Удаление всего (delete_all): защищено двойным барьером — клиентским confirm() и серверной проверкой сессии декоратором require_auth.
- Асинхронное удаление: при удалении отдельной записи используется fetch, исключая перезагрузку всей страницы.


7. Шлюз авторизации (Authentication Gate)

Модуль авторизации (login.html) построен по принципу гибридного шлюза: он обслуживает как полноценного администратора системы, так и гостевой доступ к закрытым материалам.

7.1 UX-инженерия и адаптивность

7.2 Логика перенаправлений (The Next-Pattern)

Значение целевого маршрута сохраняется в скрытом поле формы:

<input type="hidden" name="next_url" value="{{ next_url }}">

Если неавторизованный пользователь обращается к закрытому разделу, система перенаправляет его на экран входа с параметром ?next=..., а после подтверждения прав бесшовно возвращает в исходную точку.

7.3 Адаптивный шлюз доступа (Smart Access)

Шаблонизатор Jinja2 динамически меняет архитектуру формы в зависимости от параметра next_url:
- Админ-режим: отображаются стандартные поля «Логин» и «Пароль».
- Приватная статья ([P]): поле логина автоматически скрывается, а форма трансформируется в лаконичный ввод 6-значного кода доступа. Гостю не требуется знать системные учётные записи — доступ открывается строго по ключу.

7.4 Безопасность и менеджмент сессий

8. Итоги и эксплуатация

8.1 Обоснование технологического стека

  1. FastAPI: асинхронный, легковесный фреймворк с нативной валидацией и высокой скоростью отклика.
  2. Uvicorn: скоростной ASGI-сервер. В связке с директивой LimitNOFILE=65535 в systemd процесс получает расширенный пул дескрипторов, обеспечивая параллельную отдачу тяжёлых потоков без сбоев.
  3. Markdown + Vanilla JS: плоские файлы гарантируют надёжность и переносимость базы знаний, а чистый скриптовый слой исключает оверхед тяжёлых фронтенд-библиотек.
  4. Jinja2: надёжный серверный рендеринг, сохраняющий идеальное SEO без ущерба для динамического поведения.

8.2 Архитектурный вывод (The Big Picture)